package com.carnation.qa.socketserver.startup;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.carnation.qa.socketserver.common.util.MppContext;
import com.carnation.qa.socketserver.common.util.TreeParser;
import com.carnation.qa.socketserver.domain.Item;
import com.carnation.qa.socketserver.proxy.ProxyFactory;

public class ServerThread extends Thread {
	private final Log log = LogFactory.getLog(this.getClass());
	SocketListener service_;
	BufferedInputStream theInputStream = null;
	BufferedOutputStream theOutputStream = null;
	Socket Client_ = null;

	public ServerThread(SocketListener service, Socket soc) throws IOException {
		service_ = service;
		Client_ = soc;
	}

	String readPackage() throws IOException {
		int hi1Byte = theInputStream.read();
		int li2Byte = theInputStream.read();
		int lo1Byte = theInputStream.read();
		int lo2Byte = theInputStream.read();
		int length = hi1Byte << 24 | li2Byte << 16 | lo1Byte << 8 | lo2Byte;
		if (length > 0) {
			byte buff[] = new byte[length];
			int totalLength = 0;
			do {
				totalLength += theInputStream.read(buff, totalLength, length
						- totalLength);
			} while (totalLength < length);
			return new String(buff, "ISO-8859-1");

		}
		return "";
	}

	public synchronized void writePackage(String out) throws IOException {
		byte buff[] = out.getBytes("ISO-8859-1");
		int length = buff.length;
		int hi1Byte = length >> 24 & 0xff;
		int hi2Byte = length >> 16 & 0xff;
		int lo1Byte = length >> 8 & 0xff;
		int lo2Byte = length & 0xff;
		theOutputStream.write(hi1Byte);
		theOutputStream.write(hi2Byte);
		theOutputStream.write(lo1Byte);
		theOutputStream.write(lo2Byte);
		if (length > 0) {
			theOutputStream.write(buff);
		}
		theOutputStream.flush();
	}

	public void run() {
		try {
			theInputStream = new BufferedInputStream(Client_.getInputStream());
			theOutputStream = new BufferedOutputStream(Client_
					.getOutputStream());

			while (true) {
				String inputString = readPackage();
				processInput(inputString);
			}
		} catch (IOException e1) {
			// ignore this
			// if (log.isWarnEnabled()) {
			// log.warn(e1);
			// }
			// System.out.println(e1);
			shutdown();
		}
	}

	public void processInput(String in) throws IOException {
		if (log.isDebugEnabled()) {
			log.debug(in);
		}
		if (in != null && in.length() > 0) {

			TreeParser parser = new TreeParser(MppContext.getTabSeparator(),
					MppContext.getNewlineSeparator());
			List<Item> items = parser.parseTree(in);
			String label = items.get(items.size() - 1).getLabel();
			if (log.isInfoEnabled()) {
				log.info("invoke " + label);
			}
			String result = ProxyFactory.getProxy(items).run();
			if (log.isInfoEnabled()) {
				log.info("return:<" + result + ">");
			}
			// TODO transfer this to invoke moi service
			writePackage(result);
		} else {
			writePackage(in);
		}
	}

	public Socket getSocket() {
		return Client_;
	}

	public synchronized void shutdown() {
		if (Client_ != null) {
			try {
				Client_.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (service_ != null)
				service_.shudownSock(Client_);
			Client_ = null;
		}
		service_ = null;
	}
}
